package cfdt.common.utils;

import cfdt.common.enums.AlgorithmEnum;
import cfdt.common.enums.CommonCodeEnum;
import cfdt.common.exception.CodeException;
import cn.hutool.core.codec.Base64;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.encoders.Hex;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

/**
 * 哈希算法工具类
 */
public class HMacUtil {

    private HMacUtil() {
    }

    /**
     * 使用国密哈希SM3算法进行HMAC计算,响应16进制的值
     *
     * @param appKeyStr     用于HMAC计算的密钥
     * @param sourceDataStr 需要进行HMAC计算的源数据
     * @return 返回32字节的HMAC计算结果
     */
    public static String sm3Hex(String appKeyStr, String sourceDataStr) {
        byte[] appKey = appKeyStr.getBytes(StandardCharsets.UTF_8);
        byte[] sourceData = sourceDataStr.getBytes(StandardCharsets.UTF_8);
        // 计算
        byte[] hmacData = sm3(appKey, sourceData);
        // 响应16进制的值
        return Hex.toHexString(hmacData);
    }

    /**
     * 使用国密哈希SM3算法进行HMAC计算,响应base64的值
     *
     * @param appKeyStr     用于HMAC计算的密钥
     * @param sourceDataStr 需要进行HMAC计算的源数据
     * @return 返回32字节的HMAC计算结果
     */
    public static String sm3Base64(String appKeyStr, String sourceDataStr) {
        byte[] appKey = appKeyStr.getBytes(StandardCharsets.UTF_8);
        byte[] sourceData = sourceDataStr.getBytes(StandardCharsets.UTF_8);
        // 计算
        byte[] hmacData = sm3(appKey, sourceData);
        // 响应base64的值
        return Base64.encode(hmacData);
    }

    /**
     * 使用国密哈希SM3算法进行HMAC计算
     *
     * @param appKey     用于HMAC计算的密钥
     * @param sourceData 需要进行HMAC计算的源数据
     * @return 返回32字节的HMAC计算结果
     */
    public static byte[] sm3(byte[] appKey, byte[] sourceData) {
        byte[] hmacResult = new byte[32];
        HMac hmac = new HMac(new SM3Digest());
        hmac.init(new KeyParameter(appKey));
        hmac.update(sourceData, 0, sourceData.length);
        hmac.doFinal(hmacResult, 0);
        return hmacResult;
    }

    /**
     * 使用 HMAC-SHA1 签名方法对value进行签名
     * @param value 需要进行HMAC计算的源数据
     * @param key 签名Key
     * @return 返回的加密串
     */
    public static String hmacSha1(String value, String key) throws CodeException {
        try {
            // Get an hmac_sha1 key from the raw key bytes
            byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
            SecretKeySpec signingKey = new SecretKeySpec(keyBytes, AlgorithmEnum.HMAC_SHA1.getValue());

            // Get an hmac_sha1 Mac instance and initialize with the signing key
            Mac mac = Mac.getInstance(AlgorithmEnum.HMAC_SHA1.getValue());
            mac.init(signingKey);

            // Compute the hmac on input data bytes
            byte[] rawHmac = mac.doFinal(value.getBytes(StandardCharsets.UTF_8));

            // Convert raw bytes to Hex
            byte[] hexBytes = new Hex().encode(rawHmac);

            //  Covert array of Hex bytes to a String
            return new String(hexBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new CodeException(CommonCodeEnum.CODE_2002,e);
        }
    }

}
